/***********************************************************************************************************************
*                                                                                                                      *
* SPLASH build system v0.1                                                                                             *
*                                                                                                                      *
* Copyright (c) 2013 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                                 *
*                                                                                                                      *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                        *
*                                                                                                                      *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                           *
*                                                                                                                      *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                                                      *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                                                      *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                          *
*                                                                                                                      *
***********************************************************************************************************************/

#ifndef BuildGraphNode_h
#define BuildGraphNode_h

#include <unordered_set>

class BuildGraph;

/**
	@brief A single node in the build graph.
 */
class BuildGraphNode
{
public:
	BuildGraphNode(BuildGraph* graph);
	virtual ~BuildGraphNode();
	
	/**
		@brief Gets the the name of the symlink in the output directory
	 */
	virtual std::string GetOutputPath() =0;
	
	/**
		@brief Gets the hash.
		
		Calls GetHash() at most once per object across the life of the program.
	 */
	std::string GetHashCached();

	/**
		@brief Updates the node.
		
		Calls Update() at most once per object across the life of the program.
	 */
	void UpdateCached(Cluster* cluster);
	
	/**
		@brief Forcibly updates the node.
		
		Always re-runs Update() even if the node reports itself as up-to-date.
	 */
	void ForceUpdate(Cluster* cluster);
	
	/**
		@brief Gets the job ID of the build command creating this node's output.
		
		May be NULL if this node is not being rebuilt.
	 */
	ClusterJob* GetBuildJob()
	{ return m_job; }
	
	/**
		@brief Deletes the build job once the build process has completed.
		
		Used so that we don't waste time blocking on completed jobs in multi-step build/test cycles.
	 */
	void ClearBuildJob();
	
	/**
		@brief Get the output of this command.
		
		Returns true if there was output, false if nothing
	 */
	virtual bool GetOutput(std::vector<std::string>& output);
	
	/**
		@brief Gets the output of this command, hiding all output other than warnings and errors
		
		Returns true if there was output, false if nothing
	 */
	virtual bool GetFilteredOutput(std::vector<std::string>& output);
	
	/**
		@brief Gets a printable description of this node
	 */
	virtual std::string GetDescription() =0;
	
	/**
		@brief Gets the direct path to the binary in the build directory
	 */
	virtual std::string GetBinaryPath() =0;
	
	/**
		@brief Updates dependencies of this node, adding edges as necessary.
	 */
	virtual void UpdateDependencies() =0;
	
	/**
		@brief Makes a flat list of dependencies
	 */
	void ComputeFlattenedDependencies(std::unordered_set<BuildGraphNode*>& deps);
	
protected:

	/**
		@brief Removes obvious filenames from output (if compiling one source to one .o the filename is implicit, etc)
	 */
	virtual std::string RemoveImplicitFilenames(std::string line);

	/**
		@brief Gets the hash of this node's state.
		
		If a node has the same hash as another node, they are for all intents and purposes indistinguishable.
	 */
	virtual std::string GetHash() =0;
	
	/**
		@brief Updates this node and performs all required actions.
	 */
	virtual void Update(Cluster* cluster) =0;
	
	//Helper for filtering output
	virtual bool GetFilteredOutput(std::vector<std::string>& output, const char** whitelist, size_t wsize, const char** blacklist, size_t bsize);

public:
	/**
		@brief List of all nodes which must be built for this node to be built.
	 */
	std::vector<BuildGraphNode*> m_dependencies;
	
protected:
	bool m_updated;
	std::string m_cachedhash;

	BuildGraph* m_graph;
	
	ClusterJob* m_job;
};

#endif
